/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * Created on Feb 8, 2007
 */
package cesynch.crystal.synchronizer;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.crystaldecisions.sdk.exception.SDKException;
import com.crystaldecisions.sdk.framework.CrystalEnterprise;
import com.crystaldecisions.sdk.framework.IEnterpriseSession;
import com.crystaldecisions.sdk.occa.infostore.IInfoObjects;
import com.crystaldecisions.sdk.occa.infostore.IInfoStore;
import com.crystaldecisions.sdk.plugin.desktop.user.IUser;
import com.crystaldecisions.sdk.plugin.desktop.usergroup.IUserGroup;

/**
 * <p>Class represents the InfoStore from Crystal Enterprise and Business Objects. The class
 * provides the methods required for user operations in the InfoStore.</p>
 * 
 * @author <a href="mailto:cesynch@gmail.com">cesynch</a>
 */
public class InfoStore
{
    public static final String KEY_CMS_NAME = "infostore.cms.name";
    public static final String KEY_CMS_ADMIN = "infostore.admin.name";
    public static final String KEY_CMS_PASSWORD = "infostore.admin.password";
    public static final String KEY_AUTH_TYPE = "infostore.auth.type";
    
    private String cmsname;
    private String username;
    private String password;
    private String authType;
    private IEnterpriseSession es;
    private IInfoStore iStore;
    private IInfoObjects infoUsers;
    private IInfoObjects infoGroups;
    private Map groups;
    
    /**
     * <p>Constructor takes the InfoStore information needed to connect and query the 
     * InfoStore.</p>
     */
    public InfoStore(Properties p)
    {
        super();
        setCmsname(p.getProperty(KEY_CMS_NAME));
        setUsername(username = p.getProperty(KEY_CMS_ADMIN));
        setPassword(password = p.getProperty(KEY_CMS_PASSWORD));
        setAuthType(authType = p.getProperty(KEY_AUTH_TYPE));
    }
    
    /**
     * <p>Main program entry method.</p>
     * 
     * @param args program arguments.
     */
    public static void main(String[] args)
    {
        //@TODO: test / debug method
    }
    /**
     * @return Returns the cmsname.
     */
    public String getCmsname()
    {
        return cmsname;
    }
    /**
     * @param cmsname The cmsname to set.
     */
    public void setCmsname(String cmsname)
    {
        this.cmsname = cmsname;
    }
    /**
     * @return Returns the username.
     */
    public String getUsername()
    {
        return username;
    }
    /**
     * @param username The username to set.
     */
    public void setUsername(String username)
    {
        this.username = username;
    }
    /**
     * @return Returns the password.
     */
    public String getPassword()
    {
        return password;
    }
    /**
     * @param password The password to set.
     */
    public void setPassword(String password)
    {
        this.password = password;
    }
    /**
     * @return Returns the authType.
     */
    public String getAuthType()
    {
        return authType;
    }
    /**
     * @param authType The authType to set.
     */
    public void setAuthType(String authType)
    {
        this.authType = authType;
    }
    
    public void getSession() throws SDKException
    {
        if (es == null)
        {
            es = CrystalEnterprise.getSessionMgr().logon(getUsername(), getPassword(), getCmsname(), getAuthType());
            iStore = (IInfoStore) es.getService("", "InfoStore");
        }
    }
    
    public Iterator getPeopleIterator() throws SDKException
    {
        if (iStore == null)
        {
            getSession();
        }
        
        return new CEPersonIterator(getInfoUsers());
    }
    
    public Map getGroupMap() throws SDKException
    {
        if (groups == null)
        {
            groups = new HashMap();
            Iterator it = getGroupInterator();
            Group g = null;
            while (it.hasNext())
            {
                g = (Group) it.next();
                groups.put(g.getCeSI_ID(), g);
            }
        }
        return groups;
    }
    
    public Group getGroupByCeID(Integer id) throws SDKException
    {
        return (Group) getGroupMap().get(id);
    }
    
    public Iterator getGroupInterator() throws SDKException
    {
        if (iStore == null)
        {
            getSession();
        }

        //Retrieve all of the groups from the InfoStore.
        return new CEGroupIterator(getInfoGroups());
    }
    
    private IInfoObjects getInfoGroups() throws SDKException
    {
        if (infoGroups == null)
        {
            infoGroups = iStore.query( 
                    "SELECT * From CI_SYSTEMOBJECTS Where SI_PROGID='CrystalEnterprise.UserGroup'");
        }
        return infoGroups;
    }
    
    private IInfoObjects getInfoUsers() throws SDKException
    {
        if (infoUsers == null)
        {
            infoUsers = iStore.query(
                "SELECT * From CI_SYSTEMOBJECTS Where SI_PROGID='CrystalEnterprise.User'");            
        }
        return infoUsers;
    }

    class CEGroupIterator implements Iterator
    {
        private IInfoObjects ceGroups;
        private IUserGroup currentGroup;
        private int i = 0;
        
        public CEGroupIterator(IInfoObjects groups) throws SDKException
        {
            ceGroups = groups;
        }
        
        public Object next() 
        {
            Group g = new Group();
            currentGroup = (IUserGroup) ceGroups.get(i++);
            g.setName(currentGroup.getTitle());
            g.setCeSI_ID(currentGroup.getID());
            return g;
        }
        
        public boolean hasNext()
        {
            return (i < ceGroups.getResultSize())? true:false;
        }

        /**
         * @see Iterator#remove()
         */
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
    class CEPersonIterator implements Iterator
    {
        private IInfoObjects ceUsers;
        private int j = 0;
        private String[] s = null;
        private IUser ceUser = null;
        Person p = null;        
        protected CEPersonIterator(IInfoObjects usrs)
        {
            ceUsers = usrs;
        }
        
        public Object next()
        {
            try
            {
                ceUser = (IUser) ceUsers.get(j++);
                p = new Person();
                p.setUid(ceUser.getTitle());
                p.setCn(ceUser.getTitle());
                
                
                if (null == ceUser.getFullName() || "".equals(ceUser.getFullName()))
                {
                    p.setSn(ceUser.getTitle());
                    p.setGivenName("");
                }
                else
                {
                    s = StringUtils.split(ceUser.getFullName());
                    if (s.length > 1)
                    {
                        p.setGivenName(s[0]);
                        p.setSn(s[1]);
                    }
                    else
                    {
                        p.setSn(ceUser.getFullName());
                        p.setGivenName("");
                    }
                }
                p.setUserPassword(PasswordGenerator.generate());
                
                Set ceGroups = ceUser.getGroups();
                Iterator it = ceGroups.iterator();
                while (it.hasNext())
                {
                    p.addCEGroupId(it.next());
                }
                
            }
            catch (Exception e)
            {
                //TODO Log
            }
            return p;
        }
        
        public boolean hasNext()
        {
            return (j < ceUsers.getResultSize())? true:false;
        }

        /**
         * @see Iterator#remove()
         */
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
}
